home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gekkan Dennou Club 147
/
Gekkan Dennou Club - 2000.8 Vol. 147 (Japan).7z
/
Gekkan Dennou Club - 2000.8 Vol. 147 (Japan) (Track 1).bin
/
games
/
hexrev
/
think.c
< prev
Wrap
C/C++ Source or Header
|
2000-06-25
|
18KB
|
731 lines
/***************************************************
think.c : 六角リバーシ思考ルーチン
Copyright (C) 1997 - 2000 by Makoto Hiroi
****************************************************/
#include "hexrev.h"
/* 関数宣言 */
static int search_white( int, int, int );
static int finish_white( int, int );
extern const char reverse_table[546][11];
extern const short zahyou[SIZE][2];
/* 盤面の定義 */
static char board[SIZE];
static short black;
static short white;
static int space[SIZE]; /* 探索領域をセットする */
static int space_count; /* カウンタ */
static int value_table[SIZE]; /* 評価値をセットする */
static int depth; /* 探索手数 */
static int w1; /* 位置数の重み */
static int w2; /* 場所の重み */
/* 初期化データ */
static const char init_table[SIZE] = {
FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE,
FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE,
FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE,
FREE, FREE, FREE, FREE, WHITE, BLACK, FREE, FREE, FREE, FREE,
FREE, FREE, FREE, FREE, BLACK, BLACK, WHITE, FREE, FREE, FREE,
FREE, FREE, FREE, FREE, FREE, WHITE, BLACK, FREE, FREE, FREE,
FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE,
FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE,
FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE,
FREE,
};
/* 石数の表示 */
void print_stones( void )
{
_dos_c_locate( 22, 1 );
printf( "黒 %2d 個 : 白 %2d 個", black, white );
fflush( stdout );
}
/* データの初期化 */
void init_data( void )
{
int i;
const char *ptr = init_table;
for( i = 0; i < SIZE; i++, ptr++ ){
board[i] = *ptr;
}
white = 3;
black = 4;
/* 駒を置く */
_iocs_apage( 0 );
_iocs_wipe(); /* グラフィッククリア */
draw_piece( 34, WHITE );
draw_piece( 35, BLACK );
draw_piece( 44, BLACK );
draw_piece( 45, BLACK );
draw_piece( 46, WHITE );
draw_piece( 55, WHITE );
draw_piece( 56, BLACK );
/* 石数の表示 */
print_stones();
}
/* 駒を裏返すことができるか */
int check_reverse( int num )
{
int i, result = 0;
/* 6 方向をチェックする */
for( i = 0; i < DIR; i++ ){
int wc = 0, bc = 0, wf = FALSE, bf = FALSE;
const char *ptr = reverse_table[num * DIR + i];
if( *ptr == -1 ) break; /* 終了 */
do {
char content = board[*ptr];
if( content == FREE ){
break; /* 空きエリア */
} else if( content == BLACK ){
bf = TRUE;
if( !wf ) wc++;
} else {
wf = TRUE;
if( !bf ) bc++;
}
} while( *(++ptr) != -1 );
if( bf && bc ) result |= PUT_BLACK;
if( wf && wc ) result |= PUT_WHITE;
if( result == (PUT_BLACK|PUT_WHITE) ) break;
}
return result;
}
/* 石を置ける場所をセットする */
static int set_space_postion( void )
{
int i, c;
for( i = c = 0; i < SIZE; i++ ){
if( board[i] == FREE ){
space[c] = i;
value_table[c++] = NO_VALUE;
}
}
return space_count = c;
}
/* 駒を置ける場所をセットする */
static int set_piece_postion( void )
{
int i, c;
for( i = c = 0; i < SIZE; i++ ){
if( board[i] == FREE ){
space[c] = i;
value_table[c++] = NO_VALUE;
}
}
return c;
}
/* 座標から位置を求める */
int get_postion( int x, int y )
{
int i, j = set_piece_postion();
for( i = 0; i < j; i++ ){
int n = space[i];
int x1 = zahyou[n][0];
int y1 = zahyou[n][1];
if( (x1 - 17 <= x) && (x <= x1 + 17) &&
(y1 - 17 <= y) && (y <= y1 + 17)){
return n;
}
}
return -1;
}
/* 指し手があるか */
int check_move( int piece )
{
int i;
int k = (piece == BLACK) ? PUT_BLACK : PUT_WHITE;
for( i = 0; i < SIZE; i++ ){
if( board[i] != FREE ) continue;
if( check_reverse( i ) & k ) return TRUE;
}
return FALSE;
}
/* 駒を反転する */
int reverse_piece( int num, int piece, char *result )
{
int i, count = 0;
if( board[num] != FREE ) return 0; /* 石を置くことはできないよ */
/* 6 方向をチェックする */
for( i = 0; i < DIR; i++ ){
int c = count, flag = FALSE;
const char *ptr = &(reverse_table[num * DIR + i][0]);
if( *ptr == -1 ) break;
do {
int content = board[*ptr];
if( content == FREE ){
break; /* 空きエリア */
} else if( content == piece ){
flag = TRUE; break; /* 同種の駒を見つけたよ */
} else {
result[c++] = *ptr; /* 異種の駒 */
}
} while( *(++ptr) != -1 );
if( flag && (c > count) ){
count = c; /* 裏返しができたよ */
}
}
result[count] = -1; /* 終端セット */
if( count ){ /* 駒を置くことができるよ */
board[num] = piece;
for( i = 0; i < count; i++ ){
board[ result[i] ] = piece;
}
if( piece == BLACK ){
black += count + 1;
white -= count;
} else {
white += count + 1;
black -= count;
}
}
return count;
}
/* 重みテーブル */
static const int weight_table[SIZE] = {
1000, 20, 20, 20, 20, 1000,
20, 0, 1, 1, 1, 0, 20,
20, 1, 1, 1, 1, 1, 1, 20,
20, 1, 1, 1, 1, 1, 1, 1, 20,
20, 1, 1, 1, 1, 1, 1, 1, 1, 20,
1000, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1000,
20, 1, 1, 1, 1, 1, 1, 1, 1, 20,
20, 1, 1, 1, 1, 1, 1, 1, 20,
20, 1, 1, 1, 1, 1, 1, 20,
20, 0, 1, 1, 1, 0, 20,
1000, 20, 20, 20, 20, 1000,
};
/* 位置テーブル */
#define CORNER 1
static const char postion_table[SIZE] = {
CORNER, 2, 0, 0, 3, CORNER,
13, 0, 0, 0, 0, 5, 20,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0,
21, 0, 0, 0, 0, 0, 0, 0, 0, 29,
CORNER, 40, 0, 0, 0, 0, 0, 0, 0, 50, CORNER,
61, 0, 0, 0, 0, 0, 0, 0, 0, 69,
0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
70,85, 0, 0, 0, 90, 77,
CORNER, 87, 0, 0, 88, CORNER,
};
/* 評価関数(黒有利が正となる) */
static int value_func( int turn )
{
static const char corner[6] = {0, 5, 40, 50, 85, 90 };
static const char revision[6][3] = {
7, 1, 6, 11, 4, 12, 41, 30, 51, 49, 39, 60,
79, 78, 86, 83, 84, 89,
};
static const int rev_value[3] = {
150, 100, 100
};
int bv = 0, wv = 0, bc = 0, wc = 0, i;
for( i = 0; i < SIZE; i++ ){
switch( board[i] ){
case BLACK:
bv += weight_table[i]; break;
case WHITE:
wv += weight_table[i]; break;
case FREE:
if( weight_table[i] ){
int put = check_reverse( i );
if( put & PUT_BLACK ){
if( turn == BLACK && postion_table[i] == CORNER ){
bv += 250;
} else {
bc++;
}
}
if( put & PUT_WHITE ){
if( turn == WHITE && postion_table[i] == CORNER ){
wv += 250;
} else {
wc++;
}
}
}
break;
}
}
/* 隅の補正 */
for( i = 0; i < 6; i++ ){
int j;
int n = corner[i];
int k = board[n];
if( k == FREE ){
/* 隅が空いているよ */
for( j = 0; j < 3; j++ ){
int p = revision[i][j];
int v = rev_value[j];
switch( board[ p ] ){
case BLACK:
if( board[ postion_table[p] ] != BLACK ) wv += v;
break;
case WHITE:
if( board[ postion_table[p] ] != WHITE ) bv += v;
break;
}
}
} else {
/* 辺の安定性を評価(まだ不完全) */
for( j = 0; j < 2; j++ ){
int v = 0;
const char *ptr = reverse_table[n * DIR + j];
while( *ptr != -1 ){
if( k != board[*ptr++] ) break;
v += 90;
}
if( v == 450 ) v /= 2; /* 5 つとも同じ石 */
if( k == WHITE ) wv += v;
else bv += v;
}
}
}
/* 石数は逆に評価する */
return (bc - wc) * w1 + (bv - wv) + (white - black) * w2;
}
/* 結果判定 */
int result_value( int flag )
{
int value;
int wc = white;
int bc = black;
if( wc + bc == SIZE || flag == TRUE ){
if( wc == bc ){
value = 0; /* 引き分け */
} else if( bc > wc ){
value = MAX_VALUE + bc - wc; /* 黒勝ち */
} else {
value = MIN_VALUE + bc - wc; /* 白勝ち */
}
} else if( wc == 0 ){
value = MAX_VALUE + bc; /* 白全滅 */
} else if( bc == 0 ){
value = MIN_VALUE - wc; /* 黒全滅 */
} else {
value = NO_VALUE; /* 決着がついていないよ */
}
return value;
}
/* ミニマックスによる探索 */
static int search_black( int his, int limit, int pass_flag )
{
int i, point = MIN_LIMIT;
short save_white = white;
short save_black = black;
if( his == depth ){
return value_func( BLACK );
}
for( i = 0; i < space_count; i++ ){
int value, pos = space[i];
char piece_buffer[SIZE/2];
/* 駒が置いてあるかチェックする */
if( board[pos] != FREE ) continue;
/* 駒を置く */
if( !reverse_piece( pos, BLACK, piece_buffer ) ) continue;
/* 終了チェック */
if( (value = result_value( FALSE )) == NO_VALUE ){
/* 相手の手番 */
value = search_white( his + 1, point, FALSE );
}
/* 駒を元に戻す */
{
char *ptr = piece_buffer;
board[pos] = FREE;
white = save_white;
black = save_black;
do {
board[*ptr++] = WHITE;
} while( *ptr != -1 );
}
/* ミニマックス */
if( value > point ){
point = value;
}
/* αβ枝刈 */
if( point > limit ){
break;
}
}
if( point == MIN_LIMIT ){
/* 打つ手がなかった */
if( pass_flag == TRUE ){
/* 相手も打つ手なし */
point = result_value( TRUE ); /* 終了 */
} else {
/* パスだよ */
point = search_white( his, MIN_LIMIT, TRUE );
}
}
return point;
}
/* 白番 */
static int search_white( int his, int limit, int pass_flag )
{
int i, point = MAX_LIMIT;
short save_white = white;
short save_black = black;
if( his == depth ){
return value_func( WHITE );
}
for( i = 0; i < space_count; i++ ){
int value, pos = space[i];
char piece_buffer[SIZE/2];
/* 駒が置いてあるかチェックする */
if( board[pos] != FREE ) continue;
/* 駒を置く */
if( !reverse_piece( pos, WHITE, piece_buffer ) ) continue;
/* 終了チェック */
if( (value = result_value( FALSE )) == NO_VALUE ){
/* 再帰する */
value = search_black( his + 1, point, FALSE );
}
/* 駒を元に戻す */
{
char *ptr = piece_buffer;
board[pos] = FREE;
white = save_white;
black = save_black;
do {
board[*ptr++] = BLACK;
} while( *ptr != -1 );
}
/* ミニマックス */
if( point > value ){
point = value;
}
/* αβ枝刈 */
if( point < limit ){
break;
}
}
if( point == MAX_LIMIT ){
/* 打つ手がなかった */
if( pass_flag == TRUE ){
/* 相手も打つ手なし */
point = result_value( TRUE ); /* 終了 */
} else {
/* パスだよ */
point = search_black( his, MAX_LIMIT, TRUE );
}
}
return point;
}
/* 読み切り専用 */
static int finish_black( int limit, int pass_flag )
{
int i, point = MIN_LIMIT;
short save_white = white;
short save_black = black;
for( i = 0; i < space_count; i++ ){
int value, pos = space[i];
char piece_buffer[SIZE/2];
/* 駒が置いてあるかチェックする */
if( board[pos] != FREE ) continue;
/* 駒を置く */
if( !reverse_piece( pos, BLACK, piece_buffer ) ) continue;
/* 終了チェック */
if( black + white < SIZE ){
value = finish_white( point, FALSE );
} else {
value = black - white;
}
/* 駒を元に戻す */
{
char *ptr = piece_buffer;
board[pos] = FREE;
white = save_white;
black = save_black;
do {
board[*ptr++] = WHITE;
} while( *ptr != -1 );
}
/* ミニマックス */
if( value > point ){
point = value;
}
/* αβ枝刈 */
if( point > limit ){
break;
}
}
if( point == MIN_LIMIT ){
/* 打つ手がなかった */
if( pass_flag == TRUE ){
/* 相手も打つ手なし */
point = black - white; /* 終了 */
} else {
/* パスだよ */
point = finish_white( MIN_LIMIT, TRUE );
}
}
return point;
}
/* 白番 */
static int finish_white( int limit, int pass_flag )
{
int i, point = MAX_LIMIT;
short save_white = white;
short save_black = black;
for( i = 0; i < space_count; i++ ){
int value, pos = space[i];
char piece_buffer[SIZE];
/* 駒が置いてあるかチェックする */
if( board[pos] != FREE ) continue;
/* 駒を置く */
if( !reverse_piece( pos, WHITE, piece_buffer ) ) continue;
/* 終了チェック */
if( black + white < SIZE ){
value = finish_black( point, FALSE );
} else {
value = black - white;
}
/* 駒を元に戻す */
{
char *ptr = piece_buffer;
board[pos] = FREE;
white = save_white;
black = save_black;
do {
board[*ptr++] = BLACK;
} while( *ptr != -1 );
}
/* ミニマックス */
if( point > value ){
point = value;
}
/* αβ枝刈 */
if( point < limit ){
break;
}
}
if( point == MAX_LIMIT ){
/* 打つ手がなかった */
if( pass_flag == TRUE ){
/* 相手も打つ手なし */
point = black - white;
} else {
/* パスだよ */
point = finish_black( MAX_LIMIT, TRUE );
}
}
return point;
}
/* 単純挿入ソート */
static void sort( int limit )
{
int i, j;
for( i = 1; i < limit; i++ ){
int tmp_pos = space[i];
int tmp_value = value_table[i];
for( j = i - 1; j >= 0 && tmp_value > value_table[j]; j-- ){
space[j + 1] = space[j];
value_table[j + 1] = value_table[j];
}
space[j + 1] = tmp_pos;
value_table[j + 1] = tmp_value;
}
}
static void rsort( int limit )
{
int i, j;
for( i = 1; i < limit; i++ ){
int tmp_pos = space[i];
int tmp_value = value_table[i];
for( j = i - 1; j >= 0 && tmp_value < value_table[j]; j-- ){
space[j + 1] = space[j];
value_table[j + 1] = value_table[j];
}
space[j + 1] = tmp_pos;
value_table[j + 1] = tmp_value;
}
}
/* 反復深化による探索 */
static void search_move( int turn, int level )
{
int limit = set_space_postion();
short save_white = white;
short save_black = black;
if( level <= 4 ){
depth = level;
} else {
depth = 4; /* 5, 6 手先読みは反復深化を使う */
}
for( ; depth <= level; depth++ ){
int i, point = (turn == BLACK ? MIN_LIMIT : MAX_LIMIT);
for( i = 0; i < limit; i++ ){
int value, pos = space[i];
char piece_buffer[SIZE/2];
if( board[pos] != FREE ) continue;
/* 石を置く */
if( !reverse_piece( pos, turn, piece_buffer ) ) continue;
/* 終了チェック */
if( (value = result_value( FALSE )) == NO_VALUE ){
if( turn == BLACK ){
value = search_white( 1, point, FALSE );
} else {
value = search_black( 1, point, FALSE );
}
}
value_table[i] = value;
/* 元に戻す */
{
char *ptr = piece_buffer;
char piece = (turn == BLACK ? WHITE : BLACK);
white = save_white;
black = save_black;
board[pos] = FREE;
do {
board[*ptr++] = piece;
} while( *ptr != -1 );
}
if( (turn == BLACK && value > point) ||
(turn == WHITE && value < point) ){
point = value;
}
}
if( depth <= 4 ){
/* NO_VALUE を後ろに集める */
rsort( limit );
/* NO_VALUE を除外する */
while( value_table[limit - 1] == NO_VALUE ) limit--;
}
if( turn == BLACK ) sort( limit ); else rsort( limit );
}
}
/* 読み切り */
static void finish_move( int turn )
{
int limit = set_space_postion();
short save_white = white;
short save_black = black;
int i, point = (turn == BLACK ? MIN_LIMIT : MAX_LIMIT);
for( i = 0; i < limit; i++ ){
int value, pos = space[i];
char piece_buffer[SIZE];
/* 駒が置いてあるかチェックする */
if( board[pos] != FREE ) continue;
/* 駒を置く */
if( !reverse_piece( pos, turn, piece_buffer ) ) continue;
/* 終了チェック */
if( black + white < SIZE ){
if( turn == BLACK ){
value = finish_white( point, FALSE );
} else {
value = finish_black( point, FALSE );
}
} else {
value = black - white;
}
value_table[i] = value;
/* 駒を元に戻す */
{
char *ptr = piece_buffer;
char piece = (turn == BLACK ? WHITE : BLACK);
board[pos] = FREE;
white = save_white;
black = save_black;
do {
board[*ptr++] = piece;
} while( *ptr != -1 );
}
if((turn == BLACK && value > point) ||
(turn == WHITE && value < point) ){
point = value;
}
}
/* NO_VALUE を後ろに集める */
rsort( limit );
/* NO_VALUE を除外する */
while( value_table[limit - 1] == NO_VALUE ) limit--;
if( turn == BLACK ) sort( limit ); else rsort( limit );
}
/* 指手の決定 */
static int decide_move( int turn )
{
int move = 0, i = 1, v = value_table[0];
while( v == value_table[i] ) i++;
/* 同じ値の手がある */
if( i > 1 ){
/* 乱数で指手を決定する */
move = rand() % i;
}
return space[move];
}
/* 反復深化による探索 */
int select_move( int turn, int level )
{
int num = white + black;
static int finish_table[6] = {
7, 8, 9, 10, 11, 12, /* 7 はダミー */
};
/* 重みの設定 */
if( num + level > 60 ){
w1 = 30; w2 = 20;
} else if( num + level > 30 ){
w1 = 20; w2 = 20;
} else {
w1 = 20; w2 = 10;
}
/* 読み切りモードのチェック */
if( (SIZE - num) <= finish_table[level] ){
finish_move( turn );
} else {
search_move( turn, level );
}
/* 指手の決定 */
return decide_move( turn );
}
/* end of file */